/*
  Time-stamp: <2010-07-19 20:23:59 xinhaoyuan>
  File: init.c
  
  This file contains procedures for initialization of EKOS.
  
    - Initiate the physical memory allocator and manager
	- Initiate the interruption handlers
	- Enable the multitasking feature
	- Then jump into kernel main proc to continue booting
*/

#define _EKOS_KERNEL_C_

#include <kernel/kernel.h>
#include <kernel/console.h>
#include <inc/spinlock.h>

static int mem_init(void);
static int intr_init(void);
static int task_init(void);

/* This functions are implemented in kernel.S */
void kmain_asm(GPREG_T);
// void user_start(GPREG_T);

/* error message buffer */
static char err_buf[ERROR_BUF_SIZE];

void
kinit(void)
{
     /* 初始化动态分配的数据区域 */
     memset(_bss, 0, _end - _bss);

     /* 初始化基本的 IO 系统 */
     /* implemented in console subsystem */

	 console_enabled = false;
	 log_enabled = false;
	 klog_mutexed = false;

	 /* 激活控制台 */
     cons_init();
	 console_enabled = true;
	 
	 kprintf("Booting EKOS(%s)\n", EK_VER_STRING);
	 kprintf("Initializing system [\n");

     if (mem_init()) goto init_error;
     if (intr_init()) goto init_error;
     if (task_init()) goto init_error;
	 if (env_init()) goto init_error;
	 if (sch_init()) goto init_error;

	 kpipe_open(&klog_pipe);
	 log_enabled = true;

	 // keyboard driver
	 if (keyboard_init()) goto init_error;
	 // rudimental storage driver 
	 // if (ide_init()) goto init_error;

	 kprintf("]\n");

	 mutex_init(&kprintf_lock);
	 klog_mutexed = true;

     /* 任务机制已经激活, 需要重新跳转 */
     kmain_asm(envs[cur_env].cr3);

     return;
     
init_error:
     
     kprintf("There are some errors during booting EKOS.\n");
     kprintf("%s\n", err_buf);
     kprintf("Press Enter to restart.\n");
     readline(NULL);
}

/* ============================================================ */
/* MEMORY INIT */

static physaddr_t boot_free;

/* 在真正的内存模块未被初始化时的内存分配程序 */
static void *
boot_alloc(size_t size, size_t align)
{
     if (boot_free == 0)
		  boot_free = PADDR(_end);

#ifdef K_INIT_DEBUG
     kprintf("[boot_alloc] boot_free = %p, size = %d, align = 0x%x\n", boot_free, size, align);
#endif

     /* 查询第一个可以使用的内存段 */
     int lid = mlayout_bin_search(boot_free);
     lid |= 1;

     while (lid < mlayout_count)
     {
		  if (boot_free < mlayout_addr[lid - 1])
			   boot_free = mlayout_addr[lid - 1];
	  
		  /* 找到第一个可以容纳连续段的正常内存 */
		  /* 如果大小合适则跳出查找 */
		  if ((boot_free |=  align - 1) + size < mlayout_addr[lid])
			   break;
		  else lid += 2;
     }

     /* 如果找不到则返回失败 */
     if (lid >= mlayout_count) return NULL;
     /* 如果超出可访问范围则返回失败 */
     if (boot_free + size >= KSIZE) return NULL;
     else ++boot_free;

     void *result = KADDR(boot_free);
     
#ifdef K_INIT_DEBUG
     kprintf("[boot_alloc] result = %p\n", result);
#endif

     boot_free += size;

	 return result;
}

/* 此过程进行初始的内存分配 */
static int
do_boot_alloc(void)
{
     /* 计算需要管理的页个数 */
     if (mlayout_count < 2)
		  frames_count = 1 << (32 - PAGE_SHIFT);
     else frames_count = mlayout_addr[(mlayout_count - 2) | 1] / PAGE_SIZE;

#ifdef K_INIT_DEBUG
     kprintf("[do_boot_alloc] available pages: %d\n", pages_count);
#endif

     if ((frames = boot_alloc(frames_count * sizeof(struct frame_t), PAGE_SIZE)) == NULL)
		  return -E_NO_MEM;
     
     if ((envs   = boot_alloc(ENVS_MAXCOUNT * sizeof(struct env_t), PAGE_SIZE)) == NULL)
     	  return -E_NO_MEM;

     return 0;
}

/* 初始化物理内存分配 */
static void
init_pmem_allocator(void)
{

     uint32_t i, j, k, w, apages;
     bool vaild;
     physaddr_t cur;

     struct frame_t *free_head = NULL;

     apages = 0;

     cur = 0; i = 0; j = 0; k = 0;
     for (i = 0; i != frames_count; ++i)
     {

		  while (j < mlayout_count)
		  {
			   if (mlayout_addr[j] <= cur)
					++j;
			   else break;
		  }

		  while (k < mlayout_count)
		  {
			   if (mlayout_addr[k] < cur + PAGE_SIZE)
					++k;
			   else break;
		  }

		  /* 保证当前页有效 */
		  vaild = (j == k) && ((j & 1) == 1);

		  /* 初始化结构 */
		  sl_init(&frames[i].lock);
		  frames[i].ref_count = 0;
		  frames[i].flag = FRAME_FREE;
	  
		  if (vaild)
		  {
			   ++ apages;
			   /* 将当前页插入到可分配页面中去 */
			   frames[i].next = free_head;
			   free_head = frames + i;
		  }
		  else
		  {
			   frames[i].flag = FRAME_USED;
		  }
		  

		  cur += PAGE_SIZE;
     }

     /* In order to allocate memories in kernel area in booting stage,
      * we reverse the queue of free memory pages. */

     frame_free_head = NULL;
	 frame_sfree_head = NULL;
     
     while (free_head != NULL)
     {
		  struct frame_t *tmp = free_head->next;
	  
     	  free_head->next = frame_free_head;
     	  frame_free_head = free_head;
     	  free_head = tmp;
     }

#ifdef K_INIT_DEBUG
     kprintf("[init_pmem_allocator] free pages: %d\n", apages);
     kprintf(" first page number: %d\n", frame_free_head - pages);
#endif
}

/* 以下过程用来建立(重建) maplayout */

/* 内存映射的标志意义 */
#define MEMMAP_FREE        1
#define MEMMAP_RESERVED    2
#define MEMMAP_RECLAIMABLE 3
#define MEMMAP_NVS         4
#define MEMMAP_BAD         5

/* 可能的最多映射块的个数 */
#define MEMMAP_MAXCOUNT 256

static uint32_t        mmap_count;
static struct memmap_t mmap[MEMMAP_MAXCOUNT];

/* 临时使用的数组 */
static uint32_t   mmap_node_count;
static physaddr_t mmap_node_addr[MEMMAP_MAXCOUNT << 1];
static int32_t    mmap_node_flag[MEMMAP_MAXCOUNT << 1];

static void
make_mlayout(void)
{
     uint32_t i, j, k, t;

     mmap_node_count = 0;

     for (i = 0; i != mmap_count; ++i)
     {
		  mmap_node_addr[mmap_node_count] = mmap[i].base;
		  mmap_node_flag[mmap_node_count] = mmap[i].flag;
		  ++mmap_node_count;

		  /* ignore if the end overflows */
		  if (!MEMMAP_ADDR_OVERFLOW(mmap[i].end))
		  {
			   mmap_node_addr[mmap_node_count] =  mmap[i].end;
			   mmap_node_flag[mmap_node_count] = -mmap[i].flag;
			   ++mmap_node_count;
		  }
     }

     /* Sort the mmap node table */
     for (i = 0; i != mmap_node_count; ++i)
     {
		  j = i;
		  for (k = i + 1; k != mmap_node_count; ++k)
		  {
			   if (mmap_node_addr[k] < mmap_node_addr[j])
					j = k;
		  }
		  t = mmap_node_addr[i]; mmap_node_addr[i] = mmap_node_addr[j]; mmap_node_addr[j] = t;
		  t = mmap_node_flag[i]; mmap_node_flag[i] = mmap_node_flag[j]; mmap_node_flag[j] = t;
     }

     /* for debugging */
     /* for (i = 0; i != mmapNodeCount; ++i) */
     /* 	  kprintf("addr : %x, flag : %x\n", mmapNodeAddr[i], mmapNodeFlag[i]); */

     /* Make memory layout table */
     int32_t vaild_level, reclaim_level;
     bool last_vaild, v;
     
     vaild_level = 0; reclaim_level = 0; v = false;
     mlayout_count = 0;

     i = 0;
     while (1)
     {
		  if (i >= mmap_node_count) break;

		  last_vaild = v;
		  while (1)
		  {
			   switch (mmap_node_flag[i])
			   {
			   case MEMMAP_FREE:
					++vaild_level;
					break;
			   case -MEMMAP_FREE:
					--vaild_level;
					break;
			   case MEMMAP_RECLAIMABLE:
					++reclaim_level;
					break;
			   case -MEMMAP_RECLAIMABLE:
					--reclaim_level;
					break;
			   default:
					if (mmap_node_flag[i] > 0)
						 --vaild_level;
					else ++vaild_level;
			   }

			   ++i;
			   if (i >= mmap_node_count) break;
			   if (mmap_node_addr[i - 1] != mmap_node_addr[i]) break;
		  }
	  
		  if (vaild_level == 0)
			   v = (reclaim_level > 0);
		  else v = (vaild_level > 0);

		  /* for debugging */
		  // kprintf("%x %d %d %d\n", mmapNodeAddr[i - 1], vaildLevel, reclaimLevel, v);

		  if (v != last_vaild)
		  {
			   mlayout_addr[mlayout_count] = mmap_node_addr[i - 1];
			   ++mlayout_count;
		  }
     }

#ifdef K_INIT_DEBUG
     kprintf("[make_mlayout] mlayout[] =\n");
     for (i = 0; i != mlayout_count; ++i)
     {
     	  kprintf(" [%d] = %x\n", i, mlayout_addr[i]);
     }
#endif
}

static ptab_entry_t *
boot_vpd_walk(pdir_entry_t *vpd, const void *va, int create, int perm)
{
     uintptr_t pdx, ptx;
     pdx = PAGEDIR_IDX(va);
     ptx = PAGETAB_IDX(va);

     if (vpd[pdx] & PTE_P)
     {
		  /* DO NOTHING but add the perm*/
		  /* vpd[pdx] |= perm; */
     }
     else if (create)
     {
		  physaddr_t vpt;
		  /* suppose in the booting stage, all memory can be allocated
		   * in the kernel area (0 ~ 256MB) */
		  if (frame_alloc(&vpt) != 0) return NULL;
		  else frame_inc_ref(vpt);

		  memset(KADDR(vpt), 0, PAGE_SIZE);

		  vpd[pdx] = vpt | perm | PTE_P;
		  frame_inc_ref(vpt);
     }
     else
     {
		  return NULL;
     }

     return (ptab_entry_t *)KADDR(PTE_ADDR(vpd[pdx])) + ptx;
}

static void
boot_map_segment(pdir_entry_t *vpd, uintptr_t la, size_t size, physaddr_t pa, int perm)
{
     if (size == 0) return;
	 /* Here we round up */
     uintptr_t i, npages = ((size - 1) >> PAGE_SHIFT) + 1;

#ifdef K_INIT_DEBUG
     kprintf("[boot_map_segment] mapping [%x, %x] to [%x, %x]\n",
			 la, la + size - 1, pa, pa + size - 1);
#endif
     
     for (i = 0; i != npages; ++i)
     {
		  ptab_entry_t *pte;

		  pte = boot_vpd_walk(vpd, (void *)la, 1, perm);
	  
		  *pte = pa | perm | PTE_P;
	  
		  la += PAGE_SIZE;
		  pa += PAGE_SIZE;
     }
}


int
mem_init(void)
{
	 uint32_t i;
	 
     /* 初始化物理内存分配系统 */
     int err;
     
     mmap_count = *(uint32_t *)MEMMAP_BASE;
     memmove(mmap, MEMMAP_ENTRY, MEMMAP_SIZE * mmap_count);

     if (mmap_count == 0)
     {
		  snprintf(err_buf, ERROR_BUF_SIZE, "cannot detect memory map!");
		  return -E_FAULT;
     }

     for (i = 0; i != mmap_count; ++i)
		  mmap[i].end += mmap[i].base;

     /* 获得初始的内存映射 */
     make_mlayout();
     /* 初始内存分配 */
     if ((err = do_boot_alloc()) != 0) return err;

     /* mark the kernel and lower memory reserved */
     mmap[mmap_count].base = (uintptr_t)PADDR(_text);
     mmap[mmap_count].end  = boot_free;
     mmap[mmap_count].flag = MEMMAP_RESERVED;

     ++mmap_count;

     mmap[mmap_count].base = (uintptr_t)0;
     mmap[mmap_count].end =  (uintptr_t)0x00100000;
     mmap[mmap_count].flag = MEMMAP_RESERVED;

     ++mmap_count;

     /* 重新生成内存映射 */
     make_mlayout();

     /* 初始化物理内存分配器 */
     init_pmem_allocator();

     /* 下面初始化虚拟内存 */
     physaddr_t boot_cr3;
     
     memset(boot_vpd, 0, PAGEDIR_COUNT * sizeof(pdir_entry_t));
     boot_cr3 = PADDR(boot_vpd);

     boot_vpd[PAGEDIR_IDX(KVPT)] = PADDR(boot_vpd) | PTE_W | PTE_P;
     boot_vpd[PAGEDIR_IDX(UVPT)] = PADDR(boot_vpd) | PTE_U | PTE_P;

     physaddr_t ktmp;
     if ((err = frame_alloc(&ktmp)) != 0)
		  return err;
	 else frame_inc_ref(ktmp);

     boot_vpd[PAGEDIR_IDX(KTMP)] = ktmp | PTE_W | PTE_P;

     /* envs for user */
     boot_map_segment(boot_vpd, UENVS, ENVS_MAXCOUNT * sizeof(struct env_t), PADDR(envs), PTE_U);

     /* kernel stack */
     boot_map_segment(boot_vpd, KSTACK_TOP - KSTACK_SIZE, KSTACK_SIZE,
					  PADDR(boot_stack), PTE_W);
     /* mark unused part of kernel stack as unavailable */
     /* boot_map_segment(boot_vpd, KSTACK_BOT - PAGE_SIZE, */
	 /* 				  KSTACK_TOP - KSTACK_BOT + PAGE_SIZE  - KSTACK_SIZE, */
	 /* 				  KSTACK_BOT - PAGE_SIZE, 0); */
     /* kernel area */
     boot_map_segment(boot_vpd, KBASE, ~(uint32_t)KBASE + 1, 0, PTE_W);

     boot_vpd[0] = boot_vpd[PAGEDIR_IDX(KBASE)];

     // Install page table.
     lcr3(boot_cr3);

     uint32_t cr0;
     
     // Turn on paging.
     cr0 = rcr0();
     // cr0 |= CR0_PE|CR0_PG|CR0_AM|CR0_WP|CR0_NE|CR0_TS|CR0_EM|CR0_MP;
	 cr0 |= CR0_PG;
     cr0 &= ~(CR0_TS|CR0_EM);
	 
     lcr0(cr0);

     // Reload all segment registers.
     asm volatile("lgdt (%0)" : : "r"(&gdt_pd));
     asm volatile("movw %%ax,%%gs" :: "a" (GD_USER_DATA|3));
     asm volatile("movw %%ax,%%fs" :: "a" (GD_USER_DATA|3));
     asm volatile("movw %%ax,%%es" :: "a" (GD_KERN_DATA));
     asm volatile("movw %%ax,%%ds" :: "a" (GD_KERN_DATA));
     asm volatile("movw %%ax,%%ss" :: "a" (GD_KERN_DATA));
     asm volatile("ljmp %0,$1f\n 1:\n" :: "i" (GD_KERN_TEXT));  // reload cs
     asm volatile("lldt %%ax" :: "a" (0));

     boot_vpd[0] = 0;
     /* refresh the vpd */
     lcr3(boot_cr3);

     return 0;
}


/* ============================================================ */
/* INTR INIT */

static struct gatedesc_t idt[IDT_COUNT];
static struct pseudodesc_t idt_pd = {
     sizeof(idt) - 1, (unsigned long)idt
};

static void remap_irq(void);

/* reinitialize the PIC controllers, giving them specified vector offsets
   rather than 8 and 70, as configured by default */
void
remap_irq(void)
{
     /* uint8_t a1, a2; */
     
     /* a1 = inb(PIC1_DATA);                        // save masks */
     /* a2 = inb(PIC2_DATA); */
	
     outb(PIC1_COMMAND, ICW1_INIT+ICW1_ICW4);  // starts the initialization sequence
     delay();
     outb(PIC2_COMMAND, ICW1_INIT+ICW1_ICW4);
     delay();
     outb(PIC1_DATA, PICV_OFFSET1);                 // define the PIC vectors
     delay();
     outb(PIC2_DATA, PICV_OFFSET2);
     delay();
     outb(PIC1_DATA, 4);                       // continue initialization sequence
     delay();
     outb(PIC2_DATA, 2);
     delay();
	
     outb(PIC1_DATA, ICW4_8086);
     delay();
     outb(PIC2_DATA, ICW4_8086);
     delay();

	 outb(PIC1_DATA, 0xfb);
	 delay();  
     outb(PIC2_DATA, 0xff);
	 delay();
     /* outb(PIC1_DATA, a1);   // restore saved masks. */
     /* outb(PIC2_DATA, a2); */
}

int
intr_init(void)
{
     memset(idt, 0, sizeof(idt));

     uint32_t i;
     
     for (i = 0; i != 32; ++i)
     {
		  SET_GATE(idt[i] , false, GD_KERN_TEXT, isr[i], 3);
     }

     for (i = 0; i != 8; ++i)
     {
		  SET_GATE(idt[PICV_OFFSET1 + i] , false, GD_KERN_TEXT, irq[i], 3);
     }

     for (i = 0; i != 8; ++i)
     {
		  SET_GATE(idt[PICV_OFFSET2 + i] , false, GD_KERN_TEXT, irq[i + 8], 3);
     }

     /* syscall routine */
     SET_GATE(idt[INT_SYSCALL], true,  GD_KERN_TEXT, syscall, 3);
	 SET_GATE(idt[INT_YIELD],   false, GD_KERN_TEXT, int_yield, 3);
     SET_GATE(idt[INT_KCB_RET], false, GD_KERN_TEXT, kcb_ret, 3);

     /* flush the idt */
     asm volatile("lidt (%0)" : : "r"(&idt_pd));

     memset(ex_handlers, 0, sizeof(ex_handlers));
     memset(irq_handlers, 0, sizeof(irq_handlers));
	 memset(irq_pipes, 0, sizeof(irq_pipes));

	 for (i = 0; i != 16; ++i)
	 {
		  semaphore_init(irq_semaphores + i);
	 }

     /* register handler function for page fault */
     register_ex_handler(14, pfhandler);
     /* register monitor for debugging */
     register_ex_handler(3, monitor);

	 remap_irq();
	 enable_irq_line(0);

     return 0;
}

/* ============================================================ */
/* TASK INIT */

int
task_init(void)
{
     /* intialize the TSS and load it into cpu register */
     gdt[GD_TSS >> 3] = SEG16(STS_T32A, (uint32_t)&task,
							  sizeof(struct taskstate_t), 0x0);
     gdt[GD_TSS >> 3].s = 0;

     memset(&task, 0, sizeof(task));
     
     asm volatile("movw %%ss, %0 " : "=r"(task.ss0));
     task.esp0 = KSTACK_TOP;

     task.cs = GD_KERN_TEXT;
     task.ss = task.ds = task.es = task.fs = task.gs = GD_KERN_DATA | 3;

     asm volatile("ltr %%ax" :: "a" (GD_TSS|3));

     return 0;
}

/* ============================================================ */
/* ENV INIT */

int
env_init(void)
{
	 sl_init(&envs_alloc_lock);
     env_id_count = 1;

     uint32_t i;
     for (i = 0; i != ENVS_MAXCOUNT; ++i)
     {
		  memset(envs + i, 0, sizeof(struct env_t));
	  
		  envs[i].eid        = i;
		  envs[i].env_status = ENV_FREE;
		  if (i != ENVS_MAXCOUNT - 1)
			   envs[i].free_next = i + 1;
		  else envs[i].free_next = ENV_NULL;
     }
     
     env_free_head = 1;
	 env_sfree_head = ENV_NULL;

     int err;
     uint32_t perm;	 
	 physaddr_t addr;

	 pdir_entry_t *tvpd = BOOT_TVPD;
	 ptab_entry_t *tvpt = BOOT_TVPT;

	 char *tspage = BOOT_TPAGE;

	 if ((err = frame_alloc(&addr)) != 0)
	 {
		  return err;
	 }
	 else frame_inc_ref(addr);
	 
	 vpt[PAGE_NUM(tvpd)] = addr | PTE_W | PTE_P;

	 if ((err = frame_alloc(&addr)) != 0)
	 {
		  return err;
	 }
	 else frame_inc_ref(addr);
	 
	 vpt[PAGE_NUM(tvpt)] = addr | PTE_W | PTE_P;

	 if ((err = frame_alloc(&addr)) != 0)
	 {
		  return err;
	 }
	 else frame_inc_ref(addr);
	 
	 vpt[PAGE_NUM(tspage)] = addr | PTE_W | PTE_P;
	 
	 /* 我看着好像没刷新就加上这句了 ... */
	 tlbflush();
	 memset(tvpt, 0, PAGE_SIZE);
	 
	 /* 在这之后:

		TVPD: 初始的 cr3
		TVPT: 初始的 kstack 那个 4M pdir_tab
		TSPAGE: dyninfo
	 */

	 /* set the alloc table */
	 tvpt[PAGETAB_IDX(DYNINFO)] = vpt[PAGE_NUM(tspage)];
	 
	 /* set the 0 is alloced */
	 struct dyninfo_t *tmp_dyninfo = (struct dyninfo_t *)tspage;
	 for (i = 1; i < KSTACK_COUNT; ++i)
	 {
		  tmp_dyninfo->kstack_alloc_tab[i] = i + 1;
	 }
	 
	 tmp_dyninfo->kstack_alloc_free = 1;
	 tmp_dyninfo->kstack_alloc_tab[0] = KSTACK_COUNT;
	 tmp_dyninfo->kstack_alloc_inuse = 0;
	 
	 mutex_init(&tmp_dyninfo->kstack_alloc_lock);
	 mutex_init(&tmp_dyninfo->uxstack_lock);

	 tmp_dyninfo->upfhandler = 0;
	 /* 初始的权限被设定为最大 */
	 tmp_dyninfo->veflags = read_eflags() | FL_IF | FL_IOPL_MASK;
	 
     physaddr_t kstack_addr;
     /* alloc kernel stack */
     for (i = 0; i != KSTACK_SIZE >> PAGE_SHIFT; ++i)
     {	  
		  if ((err = frame_alloc(&kstack_addr)) != 0)
		  {
			   return err;
		  }
		  else frame_inc_ref(kstack_addr);
	  
		  tvpt[PAGETAB_COUNT - 1 - i] = kstack_addr | PTE_W | PTE_P;
     }

	 /* now set the uxstack */
	 physaddr_t uxstack_addr;
	 for (i = 0; i != UXSTACK_SIZE >> PAGE_SHIFT; ++i)
     {
		  
		  if ((err = frame_alloc(&uxstack_addr)) != 0)
		  {
			   return err;
		  }
		  else frame_inc_ref(uxstack_addr);

		  /* for user access */
		  tvpt[PAGETAB_IDX(UXSTACK_TOP - 1) - i] = uxstack_addr | PTE_U | PTE_W | PTE_P;
     }
	 
     physaddr_t pa = PTE_ADDR(vpt[PAGE_NUM(tvpd)]);

     /* Get a initial sketch, which has no mapping for user */
     memmove(tvpd, boot_vpd, PAGE_SIZE);

     tvpd[PAGEDIR_IDX(KVPT)] = pa | PTE_W | PTE_P;
     tvpd[PAGEDIR_IDX(UVPT)] = pa | PTE_U | PTE_P;
	 
	 /* make it accessiable for user */
     tvpd[PAGEDIR_IDX(KSTACK_TOP - 1)] = vpt[PAGE_NUM(tvpt)] | PTE_U;

	 tvpd[PAGEDIR_IDX(KTMP)] = 0;
	 /* alloc ktmp */
	 physaddr_t ktmp;
	 if ((err = frame_alloc(&ktmp)) != 0) {
	 	  return err;
	 }
	 else frame_inc_ref(ktmp);

	 tvpd[PAGEDIR_IDX(KTMP)] = ktmp | PTE_W | PTE_P;
	 /* 大概不需要清理, 不过出于道德 {{{ */
	 vpt[PAGE_NUM(tspage)] = ktmp | PTE_W | PTE_P;
	 tlbflush();
	 memset(tspage, 0, PAGE_SIZE);
	 /* }}} */
	 /* PCS 将在随后初始化 */

	 envs[0].cr3 = PTE_ADDR(vpt[PAGE_NUM(tvpd)]);

     envs[0].eid = env_id_count ++;
	 envs[0].lid = 0;
	 envs[0].env_status = ENV_INUSE;
     envs[0].ksp = task.esp0;
     envs[0].xinfo.level = 0;

	 iec_init(0);
	 
	 /* 设置权限 -- 全开 */
	 envs[0].perm_flag = PF_ADM | PF_SVP;
	 
	 return 0;
}
	 
